package com.java.stack;


import java.util.ArrayList;
import java.util.List;

/**
 * 使用栈来模拟完成一个简单的综合计算器
 *
 * @author 19252
 */
public class CalculatorStack {

    public static void main(String[] args) {
        // 需要进行计算的表达式
        // String expression = "700+20*6-48";
        String expression = "7*(2*2/5+1-50+3-4)";
        System.out.printf("表达式 7*(2*2/5+1-50+3-4) = %d \n", calculate(expression));
    }

    public static int calculate(String expression) {
        // 用于保存数字的栈
        CalculatorArrayStack numStack = new CalculatorArrayStack(20);
        // 用于保存运算符的栈
        CalculatorArrayStack operatorStack = new CalculatorArrayStack(20);
        // 用于遍历栈的指针
        int index = 0;
        // 保存数字栈第一个出栈的数字
        int val1;
        // 保存数字栈第二个出栈的数字
        int val2;
        // 用于保存操作符
        int operator = 0;
        // 运算结果
        int result;
        // 每次扫描得到的操作符
        // 对表达式进行遍历
        List<String> items = new ArrayList<>();
        String c;
        StringBuilder item = new StringBuilder();
        boolean flag = true;
        do {
            c = expression.substring(index, index + 1);
            if (operatorStack.isOperator(c) || "(".equals(c) || ")".equals(c)) {
                if (flag) {
                    items.add(String.valueOf(item));
                    item.delete(0, item.length());
                }
                items.add(c);
                flag = false;
            } else {
                item.append(c);
                if (index + 1 == expression.length()) {
                    items.add(String.valueOf(item));
                }
                flag = true;
            }
            index++;
        } while (index != expression.length());

        System.out.println("items = " + items);
        // 清空item
        item.delete(0, item.length());
        for (int i = 0; i < items.size(); i++) {
            c = items.get(i);
            if ("(".equals(c)) {
                int start = i + 1;
                int end = 0;
                for (int j = start; j < items.size(); j++) {
                    if (")".equals(items.get(j))) {
                        end = j;
                    }
                }
                item.append(expression, start, end + 1);
                System.out.println("item = " + item);
                // 递归调用
                result = calculate(String.valueOf(item));
                numStack.push(result);
                i = end + 1;
                if (i >= items.size()) {
                    break;
                } else {
                    c = items.get(i);
                }
            }
            // 如果是运算符
            if (operatorStack.isOperator(c)) {
                // 判断当前的符号栈是否为空
                flag = true;
                while (flag) {
                    if (!operatorStack.isEmpty()) {
                        // 如果符号栈中不为空，存在操作符，对将要入栈的操作符和原来栈顶的操作符优先级作比较
                        // 将要入栈的操作符优先级小于或等于栈顶的，则将栈顶的操作符出栈，并在数字栈中pop 两个数字与它进行计算
                        char operatorStackTop = (char) operatorStack.peek();
                        String oper = String.valueOf(operatorStackTop);
                        flag = operatorStack.priority(c) <= operatorStack.priority(oper);
                        if (flag) {
                            val1 = numStack.pop();
                            val2 = numStack.pop();
                            operatorStack.pop();
                            result = numStack.calculator(val1, val2, oper);
                            // 再将result 放入 numStack
                            numStack.push(result);
                        }
                    }else {
                        break;
                    }
                }
                char o = c.charAt(0);
                System.out.println("o = " + o);
                operatorStack.push(o);
            } else {
                if (!")".equals(c)) {
                    numStack.push(Integer.parseInt(c));
                }
            }

        }
        while (!operatorStack.isEmpty()) {
            val1 = numStack.pop();
            val2 = numStack.pop();
            char oper2 = (char) operatorStack.pop();
            result = numStack.calculator(val1, val2, String.valueOf(oper2));
            // 再将result 放入 numStack
            numStack.push(result);
        }
        result = numStack.pop();
        return result;
    }

}

/**
 * 栈的数组模拟
 */
class CalculatorArrayStack {

    /**
     * 栈的大小
     */
    private int maxSize;

    /**
     * 栈
     */
    private int[] stack;

    /**
     * 栈的指针
     */
    private int top = -1;

    public CalculatorArrayStack() {
    }

    /**
     * 构造函数，对栈进行初始化
     *
     * @param maxSize 栈的大小
     */
    public CalculatorArrayStack(int maxSize) {
        this.maxSize = maxSize;
        this.stack = new int[maxSize];
    }

    public int getMaxSize() {
        return maxSize;
    }

    /**
     * 设置栈的大小
     *
     * @param maxSize 栈的大小
     */
    public void setMaxSize(int maxSize) {
        this.maxSize = maxSize;
        this.stack = new int[maxSize];
    }

    /**
     * 栈的判满
     *
     * @return 栈是否满 true 已满；false 未满
     */
    public boolean isFull() {
        return top == maxSize - 1;
    }

    /**
     * 栈的判空
     *
     * @return 栈是否空 true 为空；false 不空
     */
    public boolean isEmpty() {
        return top == -1;
    }

    /**
     * 数据入栈
     *
     * @param value 数据
     */
    public void push(int value) {
        if (isFull()) {
            System.out.println("栈已满不能再添加数据！");
            return;
        }
        top++;
        stack[top] = value;
    }


    /**
     * 查看栈顶的元素值
     *
     * @return 栈顶的元素
     */
    public int peek() {
        return stack[top];
    }

    /**
     * 数据出栈
     *
     * @return 出栈的数据
     */
    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈为空，没有数据可以输出！");
        }
        int value = stack[top];
        top--;
        return value;
    }

    /**
     * 栈的遍历
     */
    public void showStack() {
        if (isEmpty()) {
            System.out.println("栈为空，没有数据可以输出！");
            return;
        }
        for (int i = top; i >= 0; i--) {
            System.out.printf("sack[%d] = %d \n", i, stack[i]);
        }
    }

    /**
     * 返回运算符的优先级
     * 优先级是由程序员自己来确定
     * 在这里优先级使用数字来表示
     * 数字越大，优先级越高
     *
     * @param operator 运算符（ASCII 中的表示）
     * @return 运算符的优先级
     */
    public int priority(String operator) {
        String multiple = "*";
        String divide = "/";
        String plus = "+";
        String minus = "-";

        if (operator.equals(multiple) || operator.equals(divide)) {
            return 1;
        } else if (operator.equals(plus) || operator.equals(minus)) {
            return 0;
        }
        // 非法符号，在这里暂时只进行加减乘除的运算
        return -1;
    }

    /**
     * 判断是否一个运算符
     *
     * @param value 传入的数字
     * @return true代表是一个运算符，false代表不是规定的运算符
     */
    public boolean isOperator(String value) {
        return "+".equals(value) || "-".equals(value) || "*".equals(value) || "/".equals(value);
    }

    /**
     * 进行计算
     *
     * @param val1     参与计算的数字
     * @param val2     参与计算的数字
     * @param operator 参与计算的操作符
     * @return 计算的结果
     */
    public int calculator(int val1, int val2, String operator) {
        // 用来保存计算的结果
        int result = 0;
        switch (operator) {
            case "+":
                result = val1 + val2;
                System.out.printf("%d %c %d = %d \n", val1, '+', val2, result);
                break;
            case "-":
                // 注意两个数的先后顺序
                result = val2 - val1;
                System.out.printf("%d %c %d = %d \n", val2, '-', val1, result);
                break;
            case "*":
                result = val1 * val2;
                System.out.printf("%d %c %d = %d \n", val1, '*', val2, result);
                break;
            case "/":
                // 注意两个数的先后顺序
                result = val2 / val1;
                System.out.printf("%d %c %d = %d \n", val2, '/', val1, result);
                break;
            default:
                break;
        }
        return result;
    }

}
